iT邦幫忙

2026 iThome 鐵人賽

DAY 9
1
Kubernetes

從零到一:使用 K8S + GitOps 打造異構技術棧的資料分析平台系列 第 9

[Day 9] 雲端評估:Always Free 額度的真實限制,以及我們決定先留在本機的理由 —— 免費不等於沒有代價,這篇記錄一次評估雲端部署、最後決定暫緩的完整過程。

  • 分享至 

  • xImage
  •  

Day 9: 雲端評估:Always Free 額度的真實限制,以及我們決定先留在本機的理由

免費不等於沒有代價,這篇記錄一次評估雲端部署、最後決定暫緩的完整過程。

1. 原本的規劃:Oracle OKE

一開始的打算跟大多數教學一樣:開一座 Oracle OKE (Kubernetes Engine) 叢集,享受託管式 K8S 的便利——Control Plane 由 Oracle 顧,我們只管 Worker Node。這個系列最初也是照著「最終會部署到 OKE」的假設在寫。

2. 撞牆一:Always Free 帳號拿不到 OKE

實際去建立叢集時,oci ce cluster create 直接回報 LimitExceeded。奇怪的是這個帳號從來沒建立過叢集,用量應該是 0 才對。查證方式很直接——oci limits value list 直接問 OCI 這個帳號在這個服務上的實際額度:

oci limits value list --service-name container-engine --compartment-id <tenancy-ocid>

回傳的 cluster-count0,不是「用完了」,是這個帳號的方案從一開始就沒有這個服務。到 Console 的 Limits 頁面把 Service 篩選器打開找 Container Engine,結果是「No matches found」——OKE 這個服務選項在篩選清單裡根本不存在。非升級版的 Always Free 帳號,Container Engine for Kubernetes 完全不在提供範圍內,不是額度用完,是這個方案本來就沒開放。

3. 備案:自架 K3s,以及 K8S 跟 K3S 的差異

既然拿不到託管式 K8S,另一條路是自己在一台 Always Free 的運算實例上裝 K3s——Rancher 開發的輕量化 K8S 發行版。

順便接續 Day 9 開頭那個 K8S numeronym 的梗:K3s 的名字其實也是雙關,不是真的照字母數砍出來的縮寫。Rancher 官方 FAQ 的說法是——他們想做一個記憶體佔用「減半」的 Kubernetes 發行版,而 Kubernetes 已經被縮寫成 K8s(10 個字母砍成 K+8+s),那乾脆把數字也砍半,8 減一半接近 3,就叫 K3s。所以 K3s 不是「Kubernetes 中間剩 3 個字母」,是刻意選一個比 8 小的數字,暗示「這是一個更小的 K8s」,梗接梗,滿有意思的。

K3s 常被拿來跟標準 K8S(例如 OKE 背後跑的那套)比較:

K8S(標準 / OKE) K3s
二進位大小 完整元件各自獨立 打包成單一 binary(<100MB)
預設儲存 etcd SQLite(單節點)/可換成外接 etcd
資源需求 較高,通常需要多顆 vCPU 輕量,單顆 vCPU、1GB 記憶體就能跑
內建元件 不含 Ingress Controller 內建 Traefik、內建 Klipper LoadBalancer
適合場景 生產叢集、多節點高可用 Edge、IoT、單節點demo、CI 測試環境
API 相容性 標準 完全相容標準 K8S API,kubectl 指令一致

K3s 對「用一台免費的小機器跑起一個能對外服務的叢集」這個需求來說是合理的選擇——它跟標準 K8S 的操作介面完全一樣,只是把 Control Plane 做得更輕,塞得進一顆 OCPU 的機器。

先確認 Always Free 的運算額度本身沒被 OKE 那個問題波及:

oci limits value list --service-name compute --compartment-id <tenancy-ocid> --all

standard-a1-core-countstandard-a1-memory-count 都還在(Ampere A1,ARM 架構,最多 4 顆 OCPU / 24GB)。準備拿其中一部分額度建一台運算實例,跑單節點 K3s。

4. 撞牆二:孤兒 Volume 吃光儲存額度

第一次嘗試建立運算實例,得到的是 QuotaExceeded: bootVolumeQuota Service limit reached。Always Free 的區域儲存額度是 200GB,照理說綽綽有餘。查下去才發現:舊 OKE 叢集刪除時,Worker Node 的 Boot Volume 跟 CSI 動態配置出來的 PV 並沒有跟著一起清乾淨——兩顆 47GB 的 Boot Volume、兩顆 50GB 的資料 Volume,全部沒有掛載在任何實例上,卻仍然算在額度裡,合計 194GB,把 200GB 幾乎吃滿。確認這 4 顆 Volume 確實沒有任何 attachment 之後,逐一刪除,釋放額度。

5. 撞牆三:Out of host capacity,撞了兩天沒過

額度騰出來後,第二個坑馬上出現:InternalError: Out of host capacity。這是 Always Free 的 Ampere A1 在熱門區域一位難求的知名問題——免費的 ARM 運算資源太搶手,建立請求常常直接被拒絕,單純是當下沒有容量分給你。

寫了一支腳本自動重試(每次失敗間隔 30~45 秒再撞一次),2 OCPU / 12GB 的規格連續重試了 16 個小時、404 次,換成更小的 1 OCPU / 6GB 規格再試,又是好幾個小時、上百次,一樣沒有成功。

6. 撞牆四:換小規格 E2.1.Micro,機器搶到了,換來的是 CPU 撐不住

A1 一直撞不到容量,換個角度:Always Free 還有另一組免費運算額度——2 台 VM.Standard.E2.1.Micro(x86_64,1 OCPU / 1GB)。這個規格不像 Ampere A1 那麼熱門,兩台都順利建立成功,湊成一個雙節點 K3s 叢集(Server + Agent),總共 2 vCPU / 2GB。

第一個問題很快出現:兩台實例在同一個 Subnet,理所當然以為節點間可以互通,結果 Agent 一直卡在加入失敗。查下去才發現,這個 Subnet 沿用的是舊 OKE 留下的 Security List,Egress 規則被限制得極窄(只允許特定 NodePort 對內網一小段 CIDR),連對外的網路請求都被擋掉,更別說 K3s API(6443)、Flannel VXLAN(8472/udp)這些跨節點必要的通訊埠。補上對外 Egress 與站內全開的 Ingress 規則後,網路層打通了。

但緊接著的第二個問題才是真正的重點:Agent 節點的連線行為從「連不到」變成「連到但被斷開」,追查 Server 節點的 K3s 日誌,看到的是一長串:

level=warning msg="Slow SQL: SELECT ... FROM kine ..." duration=13.780160273s
level=error msg="apiserver was unable to write a JSON response: http: Handler timeout"
level=error msg="Post-timeout activity" timeElapsed="1m55.393463006s" method="GET" path="/api/v1/pods"

K3s 預設用 SQLite(透過 kine 這層轉譯)當資料庫,單一節點、單一 OCPU 的情況下,一個簡單的查詢動輒要 5~14 秒,有一次 API Server 甚至等了快 兩分鐘才逾時。這台機器連 Control Plane 自己都撐不住——不是記憶體不夠(雖然 1GB 確實也很緊),是這顆 1 OCPU 的效能等級,扛不動 K3s 對 CPU 的即時性要求,哪怕還沒部署任何一個應用 Pod。

這是一個和前面三個「額度限制」性質不同的坑:前面是「拿不到資源」,這次是「拿到了資源,但這個資源的等級撐不起要跑的東西」——免費層的規格說明只會告訴你 vCPU 數字,不會告訴你這顆 vCPU 實際的運算能力夠不夠用,這種事只有真的跑起來才會知道。

7. 本機 K8S 怎麼開:Docker Desktop 設定步驟

既然這 30 天要靠本機撐過去,補一下怎麼打開它——步驟很簡單:

  1. 打開 Docker Desktop,點右上角齒輪圖示進入 Settings
  2. 左側選單找到 Kubernetes 分頁
  3. 勾選 Enable Kubernetes,按 Apply & Restart
  4. Docker Desktop 會在背景下載對應元件、用 kubeadm 拉起一個單節點叢集,第一次啟動大約需要幾分鐘

裝好之後回到左側選單的 Kubernetes 項目,就能直接看到叢集狀態:

https://ithelp.ithome.com.tw/upload/images/20260811/20182549N1tnLAgBAF.png

▲ Docker Desktop 的 Kubernetes 面板:Cluster 狀態 Active,Cluster type 是 kubeadm,單節點,版本 v1.34.1

這裡幾個資訊值得注意:Cluster type: kubeadm——代表 Docker Desktop 底層就是用標準的 kubeadm 拉起叢集,不是什麼閹割版,kubectl 對它下指令跟對雲端叢集下指令完全沒有語法差異;Nodes: 1——單節點,Control Plane 跟 Worker 是同一台機器,這也是為什麼本機開發特別適合拿來練功,沒有多節點網路配置要煩惱。裝完後 kubectl config get-contexts 會多一個 docker-desktop context,切過去就能開始下指令。

8. 純指令做法:不想點 GUI 的話

Docker Desktop 有一支 CLI(docker desktop),可以查狀態、列出 Kubernetes 用到的 image,但實測下來,這個版本沒有提供「enable kubernetes」的子指令

$ docker desktop kubernetes --help
Usage:  docker desktop kubernetes COMMAND

Manage Kubernetes

Commands:
  images      List Kubernetes images used by Docker Desktop

只有 images,沒有 enable/disable。真正能純指令切換的方法,是直接改設定檔。Windows 上 Docker Desktop 的設定存在:

%APPDATA%\Docker\settings-store.json

裡面有個 KubernetesEnabled 欄位(實測這台機器目前是 true):

$ grep -i kubernetes settings-store.json
  "KubernetesEnabled": true,

純指令啟用的流程:

docker desktop stop
# 用 CLI 工具(jq、PowerShell 的 ConvertFrom-Json/ConvertTo-Json 都行)
# 把 settings-store.json 裡的 "KubernetesEnabled" 改成 true
docker desktop start

啟動完不用開 GUI,直接用 CLI 確認狀態:

$ docker desktop status
Name                Value
Status              running
SessionID           6662814f-05e0-4a2a-99c2-5c395ae4d8cd

$ kubectl config get-contexts
CURRENT   NAME              CLUSTER           AUTHINFO
*         docker-desktop    docker-desktop    docker-desktop

$ kubectl get nodes
NAME             STATUS   ROLES           AGE   VERSION
docker-desktop   Ready    control-plane   90d   v1.34.1

實際跑起來的畫面:

https://ithelp.ithome.com.tw/upload/images/20260811/20182549n4xCrlrafH.png

▲ 純指令驗證叢集狀態:context 是 docker-desktop、node 狀態 Ready、Docker Desktop 引擎 running

kubectl get nodes 看到 Ready 就代表叢集真的活著,這一步是 GUI 版本和純指令版本共通的最終驗證方式。

節點活著只是第一步,真正要看的是上面有沒有東西在跑。查一下 Wafer BI 實際部署的 Namespace:

https://ithelp.ithome.com.tw/upload/images/20260811/20182549pjOO3N1To8.png

kubectl get pods -n k8sdemo -o wide:api-gateway、postgres、user-service、wafer-backend 四個服務都是 Running,已經穩定跑了 15 天

這才是這篇文章真正想證明的事——雖然沒有對外公開的網址,但本機這座叢集是貨真價實在跑的,不是空殼。

9. 決策:這 30 天先留在本機,雲端部署列為後續目標

到這裡要做一個務實的判斷:容量問題是 OCI 那端的資源狀態,不是我這邊能控制的變數,繼續空等下去只會拖垮整個系列的進度。決定是:這 30 天接下來的所有實戰,都在本機 Docker Desktop 的 K8S 上進行——指令、YAML、行為都跟真正的雲端叢集一致,唯一的差別是沒有對外公開的網址。

雲端部署仍然是目標,只是不是「現在」。這幾天建立的 Helm Chart(Day 10 開始)本來就是為了讓部署可以直接搬遷而設計的——不管日後是 Always Free 的 A1 容量恢復(背景重試持續進行中)、申請到 OKE,還是換一顆付費的小機器,同一份 Chart 直接 helm install 上去就是了,不需要重寫任何東西。如果 30 天結束後真的把它部署上雲,會回來這篇補上連結。

10. 小結

這篇沒有一張「成功了」的截圖,取而代之的是一連串真實撞到的限制——帳號方案本身不含 OKE、孤兒 Volume 吃光儲存額度、ARM 運算容量連續兩天缺貨,換小規格機器後又發現 CPU 效能撐不住 K3s 的 Control Plane。免費層的真實樣貌往往比廣告頁面上寫的更複雜,「有資源」跟「這個資源夠用」也是兩件不同的事,這是評估任何「免費方案」時都值得記住的一課。明天繼續往下走:用 Helm 管理 Wafer BI 的部署文件。


上一篇
[Day 8] K8S 入門:Deployment, Service 與 Namespace 的配置策略 —— 建立 K8S 基礎資源,規劃服務間的通訊路徑。
下一篇
[Day 10] Helm 管理:如何優雅地管理多服務的部署文件 —— 使用變數與 Template,告別 YAML 地獄。
系列文
從零到一:使用 K8S + GitOps 打造異構技術棧的資料分析平台17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言